use serde::{Deserialize, Serialize};
use std::fmt;
use chrono::{DateTime, Utc};

use super::enums::Direction;

/// 信号对象
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Signal {
    /// 信号字符串
    pub signal: String,
    /// score 取值在 0~100 之间，得分越高，信号越强
    pub score: i32,
    /// k1 一般是指明信号计算的K线周期，如 60分钟，日线，周线等
    pub k1: String,
    /// k2 一般是记录信号计算的参数
    pub k2: String,
    /// k3 用于区分信号，必须具有唯一性，推荐使用信号分类和开发日期进行标记
    pub k3: String,
    /// v1 是信号取值
    pub v1: String,
    /// v2 是信号取值
    pub v2: String,
    /// v3 是信号取值
    pub v3: String,
}

/// 简化的信号结构体，用于信号生成
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SimpleSignal {
    /// 信号名称
    pub name: String,
    /// 信号值
    pub value: bool,
    /// 信号方向
    pub direction: Direction,
    /// 信号时间
    pub dt: DateTime<Utc>,
}

impl Signal {
    /// 创建新的信号
    pub fn new(
        k1: String,
        k2: String,
        k3: String,
        v1: String,
        v2: String,
        v3: String,
        score: i32,
    ) -> Self {
        let signal = format!("{}_{}_{}_{}_{}_{}_{}", k1, k2, k3, v1, v2, v3, score);
        Self {
            signal,
            score,
            k1,
            k2,
            k3,
            v1,
            v2,
            v3,
        }
    }

    /// 从信号字符串创建信号
    pub fn from_signal(signal: String) -> Result<Self, String> {
        let parts: Vec<&str> = signal.split('_').collect();
        if parts.len() != 7 {
            return Err("信号格式错误，应该包含7个部分".to_string());
        }

        let score = parts[6].parse::<i32>().map_err(|_| "分数必须是整数".to_string())?;
        if score > 100 || score < 0 {
            return Err("score 必须在0~100之间".to_string());
        }

        let signal_clone = signal.clone();
        Ok(Self {
            signal: signal_clone,
            score,
            k1: parts[0].to_string(),
            k2: parts[1].to_string(),
            k3: parts[2].to_string(),
            v1: parts[3].to_string(),
            v2: parts[4].to_string(),
            v3: parts[5].to_string(),
        })
    }

    /// 获取信号名称
    pub fn key(&self) -> String {
        let mut key = String::new();
        for k in [&self.k1, &self.k2, &self.k3] {
            if k != "任意" {
                key.push_str(k);
                key.push('_');
            }
        }
        key.trim_end_matches('_').to_string()
    }

    /// 获取信号值
    pub fn value(&self) -> String {
        format!("{}_{}_{}_{}", self.v1, self.v2, self.v3, self.score)
    }

    /// 判断信号是否与信号列表中的值匹配
    pub fn is_match(&self, s: &std::collections::HashMap<String, String>) -> Result<bool, String> {
        let key = self.key();
        let v = s.get(&key).ok_or_else(|| format!("{} 不在信号列表中", key))?;
        
        let parts: Vec<&str> = v.split('_').collect();
        if parts.len() != 4 {
            return Err("信号值格式错误".to_string());
        }
        
        let score = parts[3].parse::<i32>().map_err(|_| "分数解析错误".to_string())?;
        
        if score >= self.score {
            if parts[0] == self.v1 || self.v1 == "任意" {
                if parts[1] == self.v2 || self.v2 == "任意" {
                    if parts[2] == self.v3 || self.v3 == "任意" {
                        return Ok(true);
                    }
                }
            }
        }
        Ok(false)
    }
}

impl fmt::Display for Signal {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "Signal('{}')", self.signal)
    }
}

impl SimpleSignal {
    /// 创建新的简化信号
    pub fn new(name: String, value: bool, direction: Direction, dt: DateTime<Utc>) -> Self {
        Self {
            name,
            value,
            direction,
            dt,
        }
    }
}

impl fmt::Display for SimpleSignal {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "SimpleSignal('{}', {}, {:?})", self.name, self.value, self.direction)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::collections::HashMap;

    #[test]
    fn test_signal_new() {
        let signal = Signal::new(
            "15分钟".to_string(),
            "倒0笔".to_string(),
            "方向".to_string(),
            "向上".to_string(),
            "其他".to_string(),
            "其他".to_string(),
            50,
        );

        assert_eq!(signal.score, 50);
        assert_eq!(signal.key(), "15分钟_倒0笔_方向");
        assert_eq!(signal.value(), "向上_其他_其他_50");
    }

    #[test]
    fn test_signal_from_string() {
        let signal_str = "15分钟_倒0笔_方向_向上_其他_其他_50".to_string();
        let signal = Signal::from_signal(signal_str).unwrap();

        assert_eq!(signal.score, 50);
        assert_eq!(signal.k1, "15分钟");
        assert_eq!(signal.k2, "倒0笔");
        assert_eq!(signal.k3, "方向");
        assert_eq!(signal.v1, "向上");
        assert_eq!(signal.v2, "其他");
        assert_eq!(signal.v3, "其他");
    }

    #[test]
    fn test_signal_match() {
        let signal = Signal::new(
            "15分钟".to_string(),
            "倒0笔".to_string(),
            "方向".to_string(),
            "向上".to_string(),
            "任意".to_string(),
            "任意".to_string(),
            50,
        );

        let mut signals = HashMap::new();
        signals.insert("15分钟_倒0笔_方向".to_string(), "向上_其他_其他_60".to_string());

        assert!(signal.is_match(&signals).unwrap());
    }

    #[test]
    fn test_signal_invalid_score() {
        let result = Signal::from_signal("15分钟_倒0笔_方向_向上_其他_其他_150".to_string());
        assert!(result.is_err());
    }

    #[test]
    fn test_simple_signal() {
        let dt = Utc::now();
        let signal = SimpleSignal::new(
            "测试信号".to_string(),
            true,
            Direction::Up,
            dt,
        );

        assert_eq!(signal.name, "测试信号");
        assert_eq!(signal.value, true);
        assert_eq!(signal.direction, Direction::Up);
    }
} 